/**
 * 负责把compile模块与obsever模块关联起来
 */
class Watcher {
  // vm 当前Vue实例
  // exper data中数据的key
  // cb回调 一旦数据发生了变化 需要调用cb
  constructor (vm, expr, cb) {
    this.vm= vm
    this.expr = expr
    this.cb = cb

    // this表示的就是新创建的watcher对象
    Dep.target = this
    // 把exper的就值存储起来
    this.oldValue = this.getVMValue(vm, expr)
    // 清空Dep.target
    Dep.target = null
  }

  /***********
   * 核心方法 *
   ***********/

  /**
  * 不外暴漏的方法 用于更新页面
  */
  update () {
    // 对比expr是否发生了发改变，若发生改变，调用cd
    let oldValue = this.oldValue
    let newValue = this.getVMValue(this.vm, this.expr)
    if (oldValue !== newValue) {
      this.cb(newValue, oldValue)
    }
  }

  /***********
   * 工具方法 *
   ***********/

  /**
   * 获取VM中的数据
   * @param {*} vm 
   * @param {*} expr 
   */
  getVMValue (vm , expr) {
    let data = vm.$data
    expr.split(".").forEach(key => {
      data = data[key]
    })
    return data
  }
}

/**
 * Dep对象用于管理所有的订阅者和通知这些订阅者
 */
class Dep {
  constructor () {
    // 订阅者集合
    this.subs = []
  }

  /**
   * 添加订阅者
   * @param {*} watcher 
   */
  addSub (watcher) {
    this.subs.push(watcher)
  }

  /**
   * 通知订阅者
   */
  notify () {
    // 遍历所有的订阅者 调用watcher的update方法
    this.subs.forEach(sub => sub.update())
  }
}